﻿using System;
using System.Collections.Generic;
using System.Configuration;
using Microsoft.Practices.Unity;

namespace JXT.PrimaryKey.Batman.Container.Unity
{
    /// <summary>
    /// Unity容器管理对象
    /// </summary>
    public class UnityContainer : ContainerBase {
        private static readonly object _lockObject = new object();
        private static readonly Dictionary<string, IUnityContainer> _cache = new Dictionary<string, IUnityContainer>();
        private static ContainerType _type = ContainerType.Unity;

        /// <summary>
        /// 默认构造方法
        /// </summary>
        /// <param name="name">容器名称</param>
        public UnityContainer(string name)
            : base(name) {
        }

        private IUnityContainer container;

        public override void Initialize() {
            OnInitializing(new ContainerEventsArgs(this, _type));
            IUnityContainer currentContainer = null;
            if (!_cache.TryGetValue(Name, out currentContainer))
            {
                currentContainer = new Microsoft.Practices.Unity.UnityContainer();
                object obj = ConfigurationManager.GetSection("unity");
                if (obj == null || !(obj is Microsoft.Practices.Unity.Configuration.UnityConfigurationSection))
                {
                    throw new ConfigurationErrorsException("section unity error.");
                }
                Microsoft.Practices.Unity.Configuration.UnityConfigurationSection section = obj as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection;
                //section.Containers[Name].Configure(currentContainer);
                section.Configure(currentContainer, Name);
                _cache.Add(Name, currentContainer);
            }
            container = currentContainer;
            OnInitializing(new ContainerEventsArgs(this, _type));
        }

        public override T Resolve<T>(string name = null) {
            try {
                if (container == null)
                {
                    lock (_lockObject)
                    {
                        if (container == null)
                        {
                            Initialize();
                        }
                    }
                }
                if (String.IsNullOrWhiteSpace(name))
                    return container.Resolve<T>();
                else
                    return container.Resolve<T>(name);
            } catch (Exception e) {
                OnResolveFailed(new ContainerFailedEventsArgs(this, new ContainerException(e.Message, _type, Name, e)));
                throw e;
            }
        }

        public override void TearDown() {
            OnTearDowning(new ContainerEventsArgs(this, _type));
            lock (_lockObject) {
                if (container != null) {
                    container.Dispose();
                    _cache.Remove(Name);
                }
            }
            OnTearDowed(new ContainerEventsArgs(this, _type));
        }
    }
}
